#ifndef RAGE_UTIL_CIRCULAR_BUFFER
#define RAGE_UTIL_CIRCULAR_BUFFER

/* Lock-free circular buffer.  This should be threadsafe if one thread is reading
 * and another is writing. */
template<class T>
class CircBuf
{
	T *buf;
	/* read_pos is the position data is read from; write_pos is the position
	 * data is written to.  If read_pos == write_pos, the buffer is empty.
	 *
	 * There will always be at least one position empty, as a completely full
	 * buffer (read_pos == write_pos) is indistinguishable from an empty buffer.
	 *
	 * Invariants: read_pos < size, write_pos < size. */
	unsigned size;

	/* These are volatile to prevent reads and writes to them from being optimized. */
	volatile unsigned read_pos, write_pos;

public:
	CircBuf();

	~CircBuf();
		
	/* Return the number of elements available to read. */
	unsigned num_readable() const;
	
	/* Return the number of elements writable.  Note that there must always
	 * be one */
	unsigned num_writable() const;

	unsigned capacity() const;

	void reserve( unsigned n );

	void clear();

	/* Indicate that n elements have been written. */
	void advance_write_pointer( int n );
	
	/* Indicate that n elements have been read. */
	void advance_read_pointer( int n );
	
	void get_write_pointers( T *pPointers[2], unsigned pSizes[2] );

	void get_read_pointers( T *pPointers[2], unsigned pSizes[2] );
	
	/* Write buffer_size elements from buffer, and advance the write pointer.  If
	 * the data will not fit entirely, the write pointer will be unchanged
	 * and false will be returned. */
	bool write( const T *buffer, unsigned buffer_size );

	/* Read buffer_size elements from buffer, and advance the read pointer.  If
	 * the buffer can not be filled completely, the read pointer will be unchanged
	 * and false will be returned. */
	bool read( T *buffer, unsigned buffer_size );
};

#endif

/*
 * Copyright (c) 2004 Glenn Maynard
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, and/or sell copies of the Software, and to permit persons to
 * whom the Software is furnished to do so, provided that the above
 * copyright notice(s) and this permission notice appear in all copies of
 * the Software and that both the above copyright notice(s) and this
 * permission notice appear in supporting documentation.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
 * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
 * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
 * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */
